import abc
from core.console import ColoredConsole as ccon
from core.status_logger import LogStatus as CLogger
from core.status_logger import ProgressStatus as CProgress


def print_error(*args, sep=' ', end='\n', flush=False):
    ccon.print(*args, mode=ccon.Mode.Highlight, fg=ccon.Color.Red, sep=sep, end=end, flush=flush)


def print_info(*args, sep=' ', end='\n', flush=False):
    ccon.print(*args, mode=ccon.Mode.Highlight, fg=ccon.Color.Green, sep=sep, end=end, flush=flush)


def print_warning(*args, sep=' ', end='\n', flush=False):
    ccon.print(*args, mode=ccon.Mode.Highlight, fg=ccon.Color.Yellow, sep=sep, end=end, flush=flush)


class ConsoleLog(CLogger):
    def __init__(self):
        CLogger.__init__(self)

    def write(self, msg, type: CLogger.MsgType = CLogger.MsgType.DEFAULT):
        if type is CLogger.MsgType.DEFAULT or type is CLogger.MsgType.INFO:
            print(msg, end='', flush=True)
        elif type is CLogger.MsgType.IMPORTANT or type is CLogger.MsgType.WARNING:
            print_warning(msg, end='', flush=True)
        elif type is CLogger.MsgType.ERROR:
            print_error(msg, end='', flush=True)

    def carriage_return(self):
        print('\r', end='', flush=True)

    def line_feed(self):
        print("\n", end='', flush=True)

    def backspace(self, count=1):
        print('\b', end='', flush=True)


class ConsoleProgress(CProgress):

    class StyleMaker():
        """样式构造类"""
        @abc.abstractmethod
        def __call__(self, val, width):
            pass

    class StyleChar(StyleMaker):
        def __init__(self, left, right):
            self.ch1 = left
            self.ch2 = right

        def __call__(self, val, width):
            n = int(val * width)
            return "|{}{}| {:.01%}".format(self.ch1 * n, self.ch2 * (width - n), val)

    class StyleIncrease(StyleMaker):
        def __init__(self, chars: [tuple, list]):
            self.ch0 = chars[:1]
            self.ch = chars[:-1]
            self.ch9 = chars[-1:]

        def __call__(self, val, width):
            num = int(val * width)
            if num == width:
                return "|{}| {:.01%}".format(self.ch9 * width, val)
            mod = val * width - num
            msg = "|" + self.ch9 * num
            idx = 0
            step = 1.0 / len(self.ch)
            while mod > step:
                idx += 1
                mod -= step
            return msg  + self.ch[idx] + self.ch0*(width- num - 1) + "| {:.01%}".format(val)

    def __init__(self, logger: CLogger):
        CProgress.__init__(self)
        self.logger = logger
        self.max_len = 50
        self.step = 0.01
        self.value = 0
        self.style = self.StyleChar('#', ' ')
        pass

    def _update_UI(self):
        self.logger.carriage_return()
        self.logger.write(self.style(self.value, self.max_len))

    def set_style(self, ch:str):
        ch = ch.lower()
        if ch == '*' or ch == '\\' or ch == '/':
            self.style = self.StyleIncrease(" -\\|/-\\|/*")
        elif ch == "+":
            self.style = self.StyleIncrease(" -+")
        elif ch == "★" or ch == "☆" or ch == "star":
            self.style = self.StyleChar('★', '☆')
        elif ch == "\u25cf" or ch == "\u25cb" or ch == "circle":
            self.style = self.StyleChar('\u25cf', '\u25cb')
        elif ch == "\u25a0" or ch == "\u25a1" or ch == "square":
            self.style = self.StyleChar('\u25a0', '\u25a1')
        elif ch == "\u25c6" or ch == "\u25c7" or ch == "rhombus":
            self.style = self.StyleChar('\u25c6', '\u25c7')  # 实心与空心
        elif ch == 'increase':
            self.style = self.StyleIncrease("\u00a0▏▎▍▌▋▊▉█")  # \u258f-\u2588
        elif ch == 'pillar':
            self.style = self.StyleIncrease("\u00a0▁▂▃▄▅▆▇█")  # \u2581-\u2588
        elif ch == 'fill':
            self.style = self.StyleIncrease("\u00a0░▒▓█")
        elif ch == 'windmill':
            self.style = self.StyleIncrease("\u00a0◣◤◥◢\u25a0")
        elif ch == 'ball':
            self.style = self.StyleIncrease("\u25cb\u25d4\u25d1\u25d5\u25cf")
        else:
            self.style = self.StyleChar(ch, " "*len(ch))
        pass

    def set_range(self, val):
        self.max_len = val

    def set_step(self, val):
        if isinstance(val, int) and 0 < val < self.max_len:
            self.step = val / self.max_len
        elif isinstance(val, float) and 0. < val < 1.0:
            self.step = val

    def reset_value(self):
        self.value = 0.
        self.logger.line_feed()

    def set_value(self, val):
        if isinstance(val, int):
            self.value = max(0, min(val, self.max_len)) / self.max_len
        elif isinstance(val, float):
            self.value = max(0., min(val, 1.0))
        self._update_UI()

    def get_value(self):
        return self.value

    def increase(self, count=1):
        self.value = max(0, min(self.value + self.step * count, 1.0))
        self._update_UI()


if __name__ == "__main__":
    import time
    prog = ConsoleProgress(ConsoleLog())

    prog.set_range(20)
    prog.reset_value()
    prog.set_style('(^_^)')
    for i in range(10):
        prog.set_value(i/10)
        time.sleep(0.2)
    prog.set_value(1.0)
    prog.set_range(50)
    prog.reset_value()
    prog.set_step(0.001)
    prog.set_style('pillar')
    for i in range(1000):
        prog.increase()
        time.sleep(0.01)
    prog.reset_value()
    prog.set_style('\u25a0')
    for i in range(1000):
        prog.increase()
        time.sleep(0.01)
    prog.reset_value()
    prog.set_style('\u25cf')
    for i in range(1000):
        prog.increase()
        time.sleep(0.01)
    prog.reset_value()
